"""
失物招领系统主应用文件

此文件使用 Gradio 构建了一个基于 Web 的失物招领系统界面。
用户可以上传失物图片、搜索失物以及认领物品。
系统集成了 AI 图像识别功能，能够自动识别物品标签并建议名称。

主要功能：
- 上传失物：支持图片上传，AI 自动识别标签，生成物品名称和备注
- 查找失物：根据关键词搜索已上传的失物
- 所有失物：查看所有未认领的失物列表
- 认领物品：用户可以认领找到的物品

依赖模块：
- gradio: 用于构建 Web 界面
- db_operations: 数据库操作模块
- image_recognizer: AI 图像识别模块
"""

import gradio as gr
import base64
from db_operations import (
    init_db, add_item, search_items, get_all_items,
    delete_item, item_exists
)
from image_recognizer import recognize_image_tags

def upload_and_process(image, name, location, note):
    """
    处理用户上传的失物图片和信息

    此函数接收用户上传的图片和相关信息，使用 AI 识别图片标签，
    生成最终的物品名称和备注，然后将物品保存到数据库中。

    参数：
    image (str): 上传图片的文件路径
    name (str): 用户输入的物品名称（可选）
    location (str): 物品放置地点
    note (str): 用户输入的备注信息（可选）

    返回：
    str: 处理结果消息，成功时返回确认信息，失败时返回错误提示

    处理流程：
    1. 检查图片是否上传
    2. 调用 AI 识别获取标签
    3. 确定最终物品名称（用户输入优先，否则使用 AI 识别结果）
    4. 生成备注信息（包含 AI 标签）
    5. 将图片读取为二进制数据并保存到数据库
    """
    if image is None:
        return "请上传图片"

    # 👇 核心修改：用户没输名称时，用AI识别结果的第一个词当名称
    tags = recognize_image_tags(image)  # 获取AI识别的标签（已按逗号分隔、频率排序）
    ai_name = ""
    if tags:  # 如果AI返回了结果
        # 提取第一个词作为物品名称（比如AI返回"苹果手机,手机,苹果,电话,iPhone"，取"苹果手机"）
        ai_name = tags[0].strip()

    # 最终名称：用户输入优先，没输入则用AI第一个词，还没有就提示错误
    final_name = name.strip() if name.strip() else ai_name
    if not final_name:
        return "请提供物品名称，或确保图片能被AI识别出有效名称"

    # 处理备注（保留AI所有标签）
    if tags:
        ai_note = "AI识别标签: " + ", ".join(tags)
        note = f"{note}; {ai_note}" if note else ai_note
    else:
        note = note if note else "无AI识别结果"

    # 保存到数据库
    with open(image, 'rb') as f:
        image_binary = f.read()
    add_item(image_binary, final_name, location, note)
    return f"上传成功，物品名称：{final_name}"


def format_items_html(items):
    """
    将物品列表格式化为 HTML 表格显示

    参数：
    items (list): 物品记录列表，每个记录包含 (id, image, name, location, note)

    返回：
    str: HTML 格式的表格字符串
    """
    if not items:
        return "<p>未找到匹配的失物</p>"

    html = "<table style='border-collapse: collapse; width: 100%;'>"
    html += "<tr><th style='border: 1px solid #ddd; padding: 8px;'>ID</th><th style='border: 1px solid #ddd; padding: 8px;'>图片</th><th style='border: 1px solid #ddd; padding: 8px;'>名称</th><th style='border: 1px solid #ddd; padding: 8px;'>地点</th><th style='border: 1px solid #ddd; padding: 8px;'>备注</th></tr>"

    for item_id, image_binary, name, location, note in items:
        # 将图片二进制数据编码为 base64
        image_base64 = base64.b64encode(image_binary).decode('utf-8')
        image_html = f"<img src='data:image/jpeg;base64,{image_base64}' style='max-width: 100px; max-height: 100px;'>"

        html += f"<tr><td style='border: 1px solid #ddd; padding: 8px;'>{item_id}</td><td style='border: 1px solid #ddd; padding: 8px;'>{image_html}</td><td style='border: 1px solid #ddd; padding: 8px;'>{name}</td><td style='border: 1px solid #ddd; padding: 8px;'>{location}</td><td style='border: 1px solid #ddd; padding: 8px;'>{note}</td></tr>"

    html += "</table>"
    return html


def search_items_handler(query):
    """
    处理用户搜索失物的请求

    根据用户输入的查询关键词，在数据库中搜索匹配的失物，
    并将结果格式化为 HTML 显示。

    参数：
    query (str): 用户输入的搜索关键词

    返回：
    str: HTML 格式的搜索结果
    """
    if not query.strip():
        return "<p>请输入搜索关键词</p>"

    items = search_items(query.strip())
    return format_items_html(items)



def claim_item_in_search(item_id_str, search_query):
    """
    处理在搜索页面认领物品的请求

    当用户在搜索结果中点击认领按钮时，此函数会删除数据库中对应的物品记录，
    然后重新执行搜索以更新显示结果。

    参数：
    item_id_str (str): 要认领的物品 ID 字符串
    search_query (str): 当前的搜索查询关键词，用于重新搜索

    返回：
    tuple: (重新搜索后的结果 HTML, 认领结果消息)
    """
    try:
        item_id = int(item_id_str.strip())
    except ValueError:
        return search_items_handler(search_query), "请输入有效的物品 ID"

    if item_exists(item_id):
        delete_item(item_id)
        return search_items_handler(search_query), f"物品 ID {item_id} 已成功认领"
    else:
        return search_items_handler(search_query), f"物品 ID {item_id} 不存在"


def claim_item_in_all(item_id_str):
    """
    处理在所有物品页面认领物品的请求

    当用户在所有物品列表中点击认领按钮时，此函数会删除数据库中对应的物品记录，
    然后返回更新后的所有物品列表。

    参数：
    item_id_str (str): 要认领的物品 ID 字符串

    返回：
    tuple: (更新后的所有物品 HTML 列表, 认领结果消息)
    """
    try:
        item_id = int(item_id_str.strip())
    except ValueError:
        items = get_all_items()
        return format_items_html(items), "请输入有效的物品 ID"

    if item_exists(item_id):
        delete_item(item_id)
        items = get_all_items()
        return format_items_html(items), f"物品 ID {item_id} 已成功认领"
    else:
        items = get_all_items()
        return format_items_html(items), f"物品 ID {item_id} 不存在"


# 初始化数据库
init_db()

# 创建Gradio界面
with gr.Blocks() as demo:
    gr.Markdown("### 失物招领系统")

    with gr.Tab("上传失物"):
        file = gr.Image(type="filepath", label="上传捡到的物品图片")
        name = gr.Textbox(label="物品名称")
        location = gr.Textbox(label="放置地点")
        note = gr.Textbox(label="备注信息")
        submit_upload = gr.Button("提交")
        upload_output = gr.Textbox(label="处理结果")
        submit_upload.click(upload_and_process,
                            inputs=[file, name, location, note],
                            outputs=upload_output)

    with gr.Tab("查找失物"):
        search_query = gr.Textbox(label="搜索关键词")
        search_button = gr.Button("搜索")
        search_results = gr.HTML(label="搜索结果")
        search_button.click(search_items_handler,
                            inputs=search_query,
                            outputs=search_results)

        claim_id_search = gr.Textbox(label="要认领的物品 ID")
        claim_button_search = gr.Button("认领物品")
        claim_output_search = gr.Textbox(label="认领结果")
        claim_button_search.click(claim_item_in_search,
                                  inputs=[claim_id_search, search_query],
                                  outputs=[search_results, claim_output_search])

    with gr.Tab("所有失物"):
        all_items_display = gr.HTML(value=format_items_html(get_all_items()), label="所有失物")

        claim_id_all = gr.Textbox(label="要认领的物品 ID")
        claim_button_all = gr.Button("认领物品")
        claim_output_all = gr.Textbox(label="认领结果")
        claim_button_all.click(claim_item_in_all,
                               inputs=claim_id_all,
                               outputs=[all_items_display, claim_output_all])


if __name__ == "__main__":
    demo.launch()
